package com.rankeiot.platform.service;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.rankeiot.core.util.IDUtil;
import com.rankeiot.core.util.JSONUtil;
import com.rankeiot.core.util.StringUtil;
import com.rankeiot.platform.domain.Codes;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.sagacity.sqltoy.dao.LightDao;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 编码服务
 */
@Component
@RequiredArgsConstructor
public class CodesService {
    final LightDao dao;

    Cache<String, CodeRule> rules = Caffeine.newBuilder()
            .expireAfterAccess(1, TimeUnit.MINUTES)
            .weakKeys()
            .weakValues()
            .build();
    /**
     * 获取编码
     * @param key
     * @return
     */
    public String getCode(String key) {
        CodeRule rule = rules.get(key,this::getRule);
        return rule.getValue(key);
    }

    /**
     * 添加编码规则
     * @param rule
     */
    public void saveRule(Codes rule){
        dao.save(rule);
        rules.invalidate(rule.getId());
    }
    public void deleteRule(Codes rule){
        dao.delete(rule);
        rules.invalidate(rule.getId());
    }
    public void updateRule(Codes rule){
        dao.update(rule);
        rules.invalidate(rule.getId());
    }
    /**
     * 解析规则
     * @param name
     * @return
     */
    private CodeRule getRule(String name){
        Codes codes=new Codes();
        codes.setId(name);
        codes = dao.load(codes);
        if(codes==null){
            return new SnowflakeCode(Character.MAX_RADIX);
        }
        String rules= codes.getRules();
        if(StringUtil.isEmpty(rules)){
            return new SnowflakeCode(Character.MAX_RADIX);
        }
        List<String> items= JSONUtil.parseArray(rules,String.class);
        if(items.size()==0){
            return new SnowflakeCode(Character.MAX_RADIX);
        }
        CodeRule[] ruleArr=new CodeRule[items.size()];
        for(int i=0;i<items.size();i++){
            String item=items.get(i);
            char type=item.charAt(0);
            switch (type){
                case 'C'://常量
                    ruleArr[i]=new ConstCode(item.substring(1));
                    break;
                case 'D'://日期
                    ruleArr[i]=new DateCode(item.substring(1));
                    break;
                case 'U'://雪花ID
                    ruleArr[i]=new SnowflakeCode(Integer.valueOf(item.substring(1)));
                    break;
                case 'S'://流水号
                    String[] params=item.substring(1).split(":");
                    ruleArr[i]=new SerialCode(Integer.valueOf(params[0]),Integer.valueOf(params[1]));
                    break;
                default:
                    ruleArr[i]=new SnowflakeCode(Character.MAX_RADIX);
            }
        }
        return new CombineRule(ruleArr);
    }
    /**
     * 编码规则
     */
    interface CodeRule {
        String getValue(String name);
    }

    /**
     * 常量
     */
    @AllArgsConstructor
    static class ConstCode implements CodeRule {
        //C:XXXXXXXX
        private String value;

        @Override
        public String getValue(String name) {
            return value;
        }
    }

    /**
     * 日期编码
     */
    static class DateCode implements CodeRule {
        //YYYYMMddHHmm
        //D:yyMMdd
        final private SimpleDateFormat dateFormat;
        public DateCode(String format){
            dateFormat = new SimpleDateFormat(format);
        }
        @Override
        public String getValue(String name) {
            return dateFormat.format(new Date());
        }
    }

    /**
     * 序列号编码
     * 编号,长度，编码。
     * S10:10/16/36
     */
    static class SerialCode implements CodeRule {
        final private int length;
        final private int radix;
        public SerialCode(int length,int radix){
            this.length=length;
            this.radix=radix;
        }
        @Override
        public String getValue(String name) {
            long v = SequenceIdGenerator.getMaxNo(name);
            return StringUtil.leftPad(Long.toString(v, radix).toUpperCase(), '0', length);
        }
    }

    /**
     * U 雪花编码
     */
    @AllArgsConstructor
    static class SnowflakeCode implements CodeRule {
        final private int radix;
        @Override
        public String getValue(String name) {
           long snowId= IDUtil.getSnowflakeId();
           return Long.toString(snowId,radix).toUpperCase();
        }
    }

    /**
     * 组合编码
     */
    @AllArgsConstructor
    static class CombineRule implements CodeRule {
        final private CodeRule[] rules;
        @Override
        public String getValue(String name) {
            StringBuilder sb=new StringBuilder();
            for(CodeRule cr:rules){
                sb.append(cr.getValue(name));
            }
            return sb.toString();
        }

    }
}
